package org.gc.amino.universe;

import java.awt.geom.Point2D;

public class MetaUniverseTreeNode {
	private int number_of_directions;
	private boolean has_children;
	private MetaUniverseTreeNode[] children;
	
	/** Index of current node in parent array if applicable, -1 if not */
	private int direction_number;
	/** Parent node if applicable, null if not */
	private MetaUniverseTreeNode parent;
	
	/** Time step used to create this universe */
	private float timestep;
	/** Holds current universe if applicable, null if not */
	private Universe universe;
	
	private int depth;
	
	public int getDepth() {
		return depth;
	}

	public MetaUniverseTreeNode(int number_of_directions, int depth) {
		this.depth = depth ;
		
		this.number_of_directions = number_of_directions;
		this.has_children = false;
		this.universe = null;
		this.direction_number = -1;
		this.children = new MetaUniverseTreeNode[number_of_directions];
		this.parent = null;
		
		for(int i = 0; i < number_of_directions; ++i ) {
			this.children[i] = null;
		}
	}
	
	public MetaUniverseTreeNode(MetaUniverseTreeNode parent, int number_of_directions, int number, int depth) {
		this.depth = depth;
				
		this.number_of_directions = number_of_directions;
		this.has_children = false;
		this.universe = null;
		this.direction_number = number;
		this.children = new MetaUniverseTreeNode[number_of_directions];
		this.parent = parent;
		
		for(int i = 0; i < number_of_directions; ++i ) {
			this.children[i] = null;
		}
	}

	public MetaUniverseTreeNode getParent() {
		return parent;
	}

	public void setParent(MetaUniverseTreeNode parent) {
		this.parent = parent;
	}

	public int getNumber() {
		return this.direction_number;
	}
	
	public float getTimestep() {
		return this.timestep;
	}

	public Universe getUniverse() {
		return this.universe;
	}
	
	public void setUniverse(Universe universe) {
		this.universe = universe;
	}
	
	public void removeUniverse() {
		this.universe = null;
	}
	
	public boolean hasChildren() {
		return this.has_children;
	}
	
	public boolean hasChild(int number) {
		return (this.children[number] != null);
	}
	
	public Universe makeUniverse(Point2D.Float[] possible_directions, float timestep) {
		Universe universe = null;
		
		// No parent -> root element
		if(this.parent == null) { 
			
			if(this.universe != null) {
				universe = this.universe.copy();
			}
		}
		// else -> compute from root element
		else if(this.parent.getUniverse() != null) { 
			// getting the universe from the parent
			universe = this.parent.getParent().makeUniverse(possible_directions, timestep);
			
			if(universe != null && this.direction_number != -1) {
				// selecting the direction corresponding to this.number
				Point2D.Float target_direction = possible_directions[this.direction_number];
				// moving the 'me' mote
				universe.getMe().move(target_direction, universe);
				// simulating a step
				this.timestep = timestep;
				universe.simulateStep(timestep);
			}
		}
		
		return universe;
	}

	public MetaUniverseTreeNode makeChild(int direction_number) {
		this.has_children = true;
		
		MetaUniverseTreeNode child = 
				new MetaUniverseTreeNode(this, this.number_of_directions, direction_number, this.depth +1);
		
		return child;
	}
	
	public MetaUniverseTreeNode getChild(int number) {
		return this.getChild(number);
	}
}
